﻿#region File Header
//-----------------------------------------------------------------------------
// Bricks' Bane Editor
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace BricksBaneEditor
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            brickGrid1.Wall = new Wall();
            comboBoxBrickType.Items.Clear();
            foreach (string enumName in Enum.GetNames(typeof(Brick.E_Types)))
                comboBoxBrickType.Items.Add(enumName);
            comboBoxBrickType.SelectedIndex = 0;

            lineStatusStrip.Visible = false;
        }

        #region Grid Events
        private void brickGrid1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Point clickPosition = new Point((int)Math.Floor(e.X / (float)(BrickGrid.GRID_WIDTH)) * BrickGrid.GRID_WIDTH, 
                                           (int)Math.Floor(e.Y / (float)(BrickGrid.GRID_HEIGHT)) * BrickGrid.GRID_HEIGHT);
                // Multiple add?
                if (m_IsDrawingLine)
                {
                    if (m_LineStart.HasValue)
                    {
                        int xStart = m_LineStart.Value.X;
                        int yStart = m_LineStart.Value.Y;
                        
                        Point delta = Point.Subtract(clickPosition, new Size(xStart, yStart));

                        int incrementX = 0, incrementY = 0;
                        if (Math.Abs(delta.X) >= Math.Abs(delta.Y))
                        {
                            incrementX = Math.Sign(clickPosition.X - xStart) * (brickGrid1.Wall.BrickSize.Width / BrickGrid.GRID_WIDTH);
                        }
                        else
                        {
                            incrementY = Math.Sign(clickPosition.Y - yStart) * (brickGrid1.Wall.BrickSize.Height / BrickGrid.GRID_HEIGHT);
                        }

                        if (incrementX > 0)
                        {
                            int x = xStart;
                            while (x < clickPosition.X)
                            {
                                NewBrick(new Point(x, yStart));
                                x += brickGrid1.Wall.BrickSize.Width;
                            }
                        }
                        else if (incrementX < 0)
                        {
                            int x = xStart;
                            while (x > clickPosition.X)
                            {
                                NewBrick(new Point(x, yStart));
                                x -= brickGrid1.Wall.BrickSize.Width;
                            }
                        }
                        else if (incrementY > 0)
                        {
                            int y = yStart;
                            while (y < clickPosition.Y)
                            {
                                NewBrick(new Point(xStart, y));
                                y += brickGrid1.Wall.BrickSize.Height;
                            }
                        }
                        else if (incrementY < 0)
                        {
                            int y = yStart;
                            while (y > clickPosition.Y)
                            {
                                NewBrick(new Point(xStart, y));
                                y -= brickGrid1.Wall.BrickSize.Height;
                            }
                        }

                        lineStatusStrip.Visible = false;
                        m_IsDrawingLine = false;
                    }
                    else
                    {
                        m_LineStart = clickPosition;
                        return;
                    }
                    return;
                }

                // Single add.
                NewBrick(clickPosition);
            }
            else if (e.Button == MouseButtons.Right)
            {
                Brick brick = brickGrid1.Wall.FindBrickAt(e.Location);
                if (brick != null)
                {
                    brickGrid1.Wall.Bricks.Remove(brick);
                    brickGrid1.Invalidate();
                }
            }
        }

        private void NewBrick(Point position)
        {
            Brick brick = new Brick();
            brick.Position = position;
            brick.Size = brickGrid1.Wall.BrickSize;
            brick.Color = panelBrickColor.BackColor;

            int type = comboBoxBrickType.SelectedIndex;
            if (type == -1)
                type = 0;
            brick.Type = (Brick.E_Types)type;

            brickGrid1.Wall.Bricks.Add(brick);
            brickGrid1.Invalidate();
        }

        private void brickGrid1_MouseMove(object sender, MouseEventArgs e)
        {
            int gridX = e.X / BrickGrid.GRID_WIDTH;
            int gridY = e.Y / BrickGrid.GRID_HEIGHT;
            mouseStatusStrip.Text = "(" + gridX + "," + gridY + ")";
        }

        private bool m_IsDrawingLine;
        private Point? m_LineStart;

        private void buttonLine_Click(object sender, EventArgs e)
        {
            m_IsDrawingLine = !m_IsDrawingLine;
            lineStatusStrip.Visible = m_IsDrawingLine;
            m_LineStart = null;
        }
        #endregion

        private void buttonBricksColor_Click(object sender, EventArgs e)
        {
            if (colorDialog.ShowDialog() != DialogResult.OK)
                return;

            panelBrickColor.BackColor = colorDialog.Color;
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            if (brickGrid1.Wall.Bricks.Count == 0)
                return;     // TODO: notify

            if (saveFileDialog.ShowDialog() != DialogResult.OK)
                return;

            using (StreamWriter writer = new StreamWriter(saveFileDialog.FileName))
            {
                string levelName = textBoxLevelName.Text.Trim();
                if (levelName.Length == 0)
                    writer.WriteLine("Unnamed level");
                else
                    writer.WriteLine(levelName);
                Color levelColor = panelLevel.BackColor;
                writer.WriteLine(levelColor.R + "," + levelColor.G + "," + levelColor.B);

                writer.WriteLine(brickGrid1.Wall.BrickSize.ToString());              // TODO: handle bricks sizes.

                List<Brick> bricks = new List<Brick>(256);
                bricks.AddRange(brickGrid1.Wall.Bricks);

                while (bricks.Count > 0)
                {
                    Brick.E_Types type = bricks[0].Type;
                    writer.WriteLine(type.ToString());
                    Color color = bricks[0].Color;
                    writer.WriteLine("Color");
                    writer.WriteLine(color.R + "," + color.G + "," + color.B);
                    WriteBricks(ref bricks, writer, type, color);
                }

                writer.Flush();
            }
        }

        private void WriteBricks(ref List<Brick> bricks, StreamWriter writer, Brick.E_Types type, Color color)
        {
            int idx = 0;
            while (idx < bricks.Count)
            {
                Brick brick = bricks[idx];
                if (brick.Color == color && bricks[idx].Type == type)
                {
                    writer.WriteLine((brick.Position.X / 8) + "," + (brick.Position.Y / 8));
                    bricks.RemoveAt(idx);
                    continue;
                }

                idx++;
            }
        }

        private void buttonLoad_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() != DialogResult.OK)
                return;

            using (StreamReader reader = new StreamReader(openFileDialog.FileName))
            {
                textBoxLevelName.Text = reader.ReadLine();
                panelLevel.BackColor = ReadColor(reader.ReadLine());
                string brickSize = reader.ReadLine();

                List<Brick> bricks = new List<Brick>(256);

                string[] enumNames = Enum.GetNames(typeof(Brick.E_Types));
                Color color = Color.Magenta;
                Brick.E_Types type = Brick.E_Types.Basic;
                while (!reader.EndOfStream)
                {
                    string line = reader.ReadLine();
                    if (line == "Color")
                    {
                        color = ReadColor(reader.ReadLine());
                        continue;
                    }
                    if (line.IndexOf(',') == -1)
                    {
                        if (Array.IndexOf(enumNames, line) != -1)
                            type = (Brick.E_Types)Enum.Parse(typeof(Brick.E_Types), line, true);
                        continue;
                    }

                    Brick brick = ReadBrick(line, type, color);
                    bricks.Add(brick);
                }

                brickGrid1.Wall.Bricks.Clear();
                brickGrid1.Wall.Bricks.AddRange(bricks);
                brickGrid1.Invalidate();

                bricks.Clear();
            }
        }

        private Brick ReadBrick(string line, Brick.E_Types type, Color color)
        {
            Brick brick = new Brick();
            brick.Color = color;
            string[] elements = line.Split(',');
            brick.Position = new Point(int.Parse(elements[0]) * 8, int.Parse(elements[1]) * 8);
            brick.Size = brickGrid1.Wall.BrickSize;
            brick.Type = type;
            return brick;
        }

        private void buttonLevelColor_Click(object sender, EventArgs e)
        {
            if (colorDialog.ShowDialog() != DialogResult.OK)
                return;

            panelLevel.BackColor = colorDialog.Color;
        }

        private static Color ReadColor(string colorStr)
        {
            string[] elements = colorStr.Split(',');
            return Color.FromArgb(255, int.Parse(elements[0]), int.Parse(elements[1]), int.Parse(elements[2]));
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            textBoxLevelName.Text = "";
            panelBrickColor.BackColor = Color.White;
            panelLevel.BackColor = Color.Black;
            brickGrid1.Wall = new Wall();
            brickGrid1.Invalidate();
            comboBoxBrickType.SelectedIndex = 0;
        }

        private void buttonMoveUp_Click(object sender, EventArgs e)
        {
            MoveAllBricks(new Size(0, -8));
        }

        private void buttonMoveDown_Click(object sender, EventArgs e)
        {
            MoveAllBricks(new Size(0, 8));
        }

        private void buttonMoveRight_Click(object sender, EventArgs e)
        {
            MoveAllBricks(new Size(8, 0));
        }

        private void buttonMoveLeft_Click(object sender, EventArgs e)
        {
            MoveAllBricks(new Size(-8, 0));
        }

        private void MoveAllBricks(Size delta)
        {
            foreach (Brick brick in brickGrid1.Wall.Bricks)
            {
                brick.Position += delta;
            }
            brickGrid1.Invalidate();
        }
    }
}
